package com.wtp.wallpaper.utils;

import com.aliyun.oss.*;
import com.aliyun.oss.internal.OSSConstants;
import com.aliyun.oss.model.*;
import com.wtp.wallpaper.common.constant.PictureOssPathConstant;
import io.netty.util.internal.StringUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class AliOssUtil {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    private String downloadDir = PictureOssPathConstant.DEFAULT_TEMP; // 默认下载临时目录

    public AliOssUtil(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {
        this.endpoint = endpoint;
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
        this.bucketName = bucketName;
    }

    private OSS ossClient = null;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @PostConstruct
    public void init() {
        this.ossClient = new OSSClientBuilder()
                .build(endpoint, accessKeyId, accessKeySecret);
    }
    @PreDestroy
    public void shutdown() {
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }

    public String upload(String fileName,String objectName){
        return upload(getByteArr(new File(fileName)),objectName);
    }

    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

//        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);
        return stringBuilder.toString();
    }

    public String getCachedUrl(String originalUrl) {
        if (StringUtil.isNullOrEmpty(originalUrl)) return originalUrl;

        String cachedUrl = redisTemplate.opsForValue().get(originalUrl);
        if (cachedUrl == null) {
            cachedUrl = generatePresignedUrl(originalUrl);
            redisTemplate.opsForValue().set(
                    originalUrl,
                    cachedUrl,
                    2,
                    TimeUnit.HOURS
            );
        }
        return cachedUrl;
    }

    private String generatePresignedUrl(String objectName) {
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 设置URL的过期时间为2小时
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000 * 2);
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
        request.setExpiration(expiration);
        URL url = ossClient.generatePresignedUrl(request);
        return url.toString();
    }

    public void removeByPrefix(String prefix){


        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 列举所有包含指定前缀的文件并删除。
        String nextMarker = null;
        ObjectListing objectListing = null;
        do {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
                    .withPrefix(prefix)
                    .withMarker(nextMarker);

            objectListing = ossClient.listObjects(listObjectsRequest);
            if (!objectListing.getObjectSummaries().isEmpty()) {
                List<String> keys = new ArrayList<String>();
                for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
                    System.out.println("key name: " + s.getKey());
                    keys.add(s.getKey());
                }
                DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(keys).withEncodingType("url");
                DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteObjectsRequest);
                List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
                for(String obj : deletedObjects) {
                    String deleteObj =  URLDecoder.decode(obj, StandardCharsets.UTF_8);
                    System.out.println(deleteObj);
                }
            }

            nextMarker = objectListing.getNextMarker();
        } while (objectListing.isTruncated());

    }

    public void remove(List<String> filenames){
        // 创建OSSClient实例。
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        DeleteObjectsResult deleteObjectsResult  = ossClient.deleteObjects(
                new DeleteObjectsRequest(bucketName)
                        .withKeys(filenames)
                        .withEncodingType("url"));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
        for (String deletedObject : deletedObjects) {
            String deleteObj = null;
            try {
                deleteObj = URLDecoder.decode(deletedObject, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            System.out.println(deleteObj);
        }

    }
    public void remove(String filename){
        // 创建OSSClient实例。
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.deleteObject(bucketName,filename);
    }

    public void uploadImage(String filePath, String objectName) {
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 将Windows路径中的反斜杠替换为正斜杠
        String normalizedFilePath = filePath.replace("\\", "/");

        // 创建ObjectMetadata实例并设置Content-Type
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType("image/png");  // 根据你的文件类型调整

        // 创建PutObjectRequest，并将ObjectMetadata传递进去
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(normalizedFilePath));
        putObjectRequest.setMetadata(metadata);  // 设置元数据

        ossClient.putObject(putObjectRequest);
    }

    public byte[] getByteFromOSS(String objectPath) throws IOException {
        return ossClient.getObject(bucketName, objectPath).getObjectContent().readAllBytes();
    }

    /**
     * 根据 OSS 文件路径下载文件并返回本地临时 File 对象
     * @param objectPath OSS 文件路径（如 "folder/file.txt"）
     * @return 本地临时 File 对象
     * @throws IOException 下载失败或文件操作异常时抛出
     */
    public File getFileFromOSS(String objectPath) throws IOException {

        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 确保下载目录存在
        File targetDir = new File(downloadDir);
        if (!targetDir.exists() && !targetDir.mkdirs()) {
            PictureReduceUtil.createDir(targetDir.getPath());
        }
        // 提取原始文件名
        String fileName = getFileName(objectPath);
        File localFile = new File(targetDir, fileName);
        try {
            OSSObject ossObject = ossClient.getObject(bucketName, objectPath);
            // 将文件流写入本地文件（覆盖已存在文件）
            try (InputStream inputStream = ossObject.getObjectContent()) {
                Files.copy(inputStream, localFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            }
            return localFile;
        } catch (OSSException | com.aliyun.oss.ClientException e) {
            throw new IOException("Failed to download file from OSS: " + e.getMessage(), e);
        }
    }

    // 提取文件名（兼容带路径和不带路径的情况）
    private String getFileName(String objectPath) {
        return objectPath.contains("/") ?
                objectPath.substring(objectPath.lastIndexOf('/') + 1) :
                objectPath;
    }

    private byte[] getByteArr(File file){ //获取文件字节数组
        byte[] b = new byte[(int)file.length()];
        try {
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
            in.read(b);
            in.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return b;
    }

}
